﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;

namespace Expression表达式目录树
{
    /// <summary>
    /// 词典方法推展
    /// </summary>
    public class DictionariesExpand<T, TOut>
    {
        /// <summary>
        /// 创建一个静态的容器存放委托
        /// </summary>
        private static Dictionary<string, Func<T, TOut>> pairs = new Dictionary<string, Func<T, TOut>>();

        /// <summary>
        /// 转换对象
        /// </summary>
        /// <typeparam name="T">输入对象</typeparam>
        /// <param name="obj">输入参数</param>
        /// <returns></returns>
        public static TOut ToObj(T obj)
        {
            //生成
            string key = typeof(T).FullName + typeof(TOut).FullName;
            if (!pairs.ContainsKey(key))
            {
                //首先我们还是创建一个参数
                ParameterExpression parameter = Expression.Parameter(typeof(T));
                //获取要转化后的类型
                Type type = typeof(TOut);
                //创建一个容器存放解析的成员
                List<MemberBinding> list = new List<MemberBinding>();
                //遍历属性
                foreach (var item in type.GetProperties())
                {
                    //获取参数中item.Name对应的名称
                    MemberExpression memberExpression = Expression.Property(parameter, typeof(T).GetProperty(item.Name));
                    //判断是否存在
                    if (memberExpression != null)
                    {
                        MemberBinding member = Expression.Bind(item, memberExpression);
                        list.Add(member);
                    }
                }
                //遍历字段
                foreach (var item in type.GetFields())
                {
                    //获取参数中item.Name对应的名称
                    MemberExpression memberExpression = Expression.Field(parameter, typeof(T).GetField(item.Name));
                    //判断是否存在
                    if (memberExpression != null)
                    {
                        MemberBinding member = Expression.Bind(item, memberExpression);
                        list.Add(member);
                    }
                }
                //初始化转换后的类型，并且进行初始化赋值
                MemberInitExpression memberInit = Expression.MemberInit(Expression.New(typeof(TOut)), list);
                //所有的准备工作已经完成准备生成lambda
                Expression<Func<T, TOut>> expression = Expression.Lambda<Func<T, TOut>>(memberInit, new ParameterExpression[] {
                parameter
                });
                Func<T, TOut> entrust = expression.Compile();
                //生成委托存放到我们的字典
                pairs.Add(key, entrust);
                return entrust.Invoke(obj);
            }
            return pairs[key].Invoke(obj);
        }
    }
}
